//
//  MusicPlayerManager.swift
//  NDAi
//
//  Created by 丸子 on 2024/7/26.
//

import UIKit
import AVFoundation
import MediaPlayer

enum SUPlayerState:Int {
    case SUPlayerStateWaiting
    case SUPlayerStatePlaying
    case SUPlayerStatePaused
    case SUPlayerStateStopped
    case SUPlayerStateBuffering
    case SUPlayerStateError
}

class MusicPlayerManager:NSObject {
    static let shared = MusicPlayerManager()
    /* 列表 */
    var dataSource:[MusicModel] = []
    /* 当前模型 */
    var currendModel:MusicModel?
    /* 是否播放完成 */
    var isPlayerDone:Bool = false
    /* 播放状态 */
    var playState:SUPlayerState = .SUPlayerStateWaiting {
        didSet {
            GlobalRx.playStateSubject.accept(playState)
        }
    }    /* 播放器 */
    var musicPlayer:AVPlayer?
    
    var timeObserverToken: Any?
    
    override init() {
        super.init()
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(.playback)
            try session.setActive(true)
        }catch { }
        NotificationCenter.default.addObserver(forName: UIApplication.willTerminateNotification, object: nil, queue: OperationQueue.main) { [weak self] _ in
            // 停止视频
            //            self?.videoPlayer.stop()
            // 设置锁屏信息
            //            self?.updateLockScreenInfo()
        }
        
    }
    func startPlayMusic(model: MusicModel? = nil) {
        if let model = model {
            if let index = self.dataSource.firstIndex(where: { $0.id == model.id}) {
                self.playMusicWithModel(dataSource[index])
            }else {
                self.dataSource.append(model)
                self.playMusicWithModel(model)
            }
        }else {
            if !self.dataSource.isEmpty {
                self.playMusicWithModel(dataSource.first!)
            }
        }
    }
    func playMusicWithModel(_ model: MusicModel?) {
        guard let model = model else { return }
        // 首先确保 currendModel 和 model 都不为 nil
        guard let modelId = model.id else {
            return
        }
        let isSameId = (currendModel?.id ?? 0) == modelId
        let isPlaying = playState == .SUPlayerStatePlaying
        if isSameId && isPlaying {
            self.musicPlayer?.play()
            XLog.d("", "恢复播放")
            return
        }
        self.removeCurrent()
        self.currendModel = model
        GlobalRx.updateMusicInfo.accept(model)//更新封面信息
        playAundioWithFileName(model.music_url ?? "")
    }
    
    func playAundioWithFileName(_ urlString: String) {
        musicPlayer?.removeObserver(self, forKeyPath: "rate")
        if urlString.contains("http") {
            var playItem: AVPlayerItem = AVPlayerItem(url: URL(string: urlString)!)
            musicPlayer = AVPlayer(playerItem: playItem)
            musicPlayer?.play()
            addObserver()
            addPeriodicTimeObserver()
            updateLockScreenInfo()
        }
    }
    func addObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: AVAudioSession.interruptionNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(stopAudio), name: .AVPlayerItemDidPlayToEndTime, object: musicPlayer?.currentItem)
        musicPlayer?.currentItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status),options: [.old, .new], context: nil)
        musicPlayer?.addObserver(self, forKeyPath: "rate", options: .new, context: nil)
        
        musicPlayer?.addObserver(self, forKeyPath: "timeControlStatus", options: [.new, .old], context: nil)
        musicPlayer?.currentItem?.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: [.new, .old], context: nil)
    }
    func removeObserver() {
        NotificationCenter.default.removeObserver(self, name: AVAudioSession.interruptionNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: musicPlayer?.currentItem)
        musicPlayer?.currentItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status))
        musicPlayer?.removeObserver(self, forKeyPath: "rate")
        musicPlayer?.currentItem?.removeObserver(self, forKeyPath: "status")
        musicPlayer?.currentItem?.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
    }
    func addPeriodicTimeObserver() {
        // Invoke callback every half second
        let time = CMTimeMake(value: 1, timescale: 1)
        timeObserverToken = musicPlayer?.addPeriodicTimeObserver(forInterval: time, queue: .main) { [weak self] time in
            // Update progress bar here
            if UIApplication.shared.applicationState != .background {
                guard let self = self else { return }
                let duration = self.musicPlayer?.currentItem?.duration.seconds ?? 0
                let currentTime = time.seconds
                let progress = currentTime / duration
                let currentMinutes = Int(currentTime) / 60
                let currentSeconds = Int(currentTime) % 60
                if !duration.isNaN {
                    let totalMinutes = Int(duration) / 60
                    let totalSeconds = Int(duration) % 60
                    // Format the time strings
                    let currentTimeString = String(format: "%02d:%02d", currentMinutes, currentSeconds)
                    let totalDurationString = String(format: "%02d:%02d", totalMinutes, totalSeconds)
                    GlobalRx.updateMusicProgress.accept((currentTimeString, totalDurationString, Float(progress)))
                }
            }
        }
    }
    @objc func handleInterruption(notification: Notification) {
        guard let userInfo = notification.userInfo,
              let type = userInfo[AVAudioSessionInterruptionTypeKey] as? AVAudioSession.InterruptionType else {
            return
        }
        switch type {
        case .began:
            pauseCurrentMusic()
        case .ended:
            if let options = userInfo[AVAudioSessionInterruptionOptionKey] as? AVAudioSession.InterruptionOptions,
               options.contains(.shouldResume) {
                playCurrentMusic()
            }
        @unknown default:
            break
        }
    }
    @objc func stopAudio(_ not:Notification) {
        self.removeCurrent()
        guard not.name == Notification.Name.AVPlayerItemDidPlayToEndTime else { return }
//        nextMusic()
    }
    
    /**
     * 暂停
     */
    func pauseCurrentMusic()
    {
        playState = .SUPlayerStatePaused
        musicPlayer?.pause()
        isPlayerDone = false
    }
    
    func playCurrentMusic() {
        if playState == .SUPlayerStateStopped {
            nextMusic()
            return
        }else {
            transformMusicState(state: .SUPlayerStatePlaying)
        }
        isPlayerDone = false
    }
    
    
    func removeCurrent() -> Void {
        playState = .SUPlayerStateStopped
        self.currendModel = nil
        isPlayerDone = true
        GlobalRx.musicRemoveObserverSubject.onNext(())
        if let token = timeObserverToken {
            self.musicPlayer?.removeTimeObserver(token)
        }
//        self.removeObserver()
        self.musicPlayer?.pause()
        self.musicPlayer?.rate = 0
        self.musicPlayer = nil
    }
    
    func nextMusic() {
        self.removeCurrent()
        updateMusicIndex(increment: true)
        transformMusicState(state: .SUPlayerStatePlaying)
    }
    func preMusic() {
        self.removeCurrent()
        updateMusicIndex(increment: false)
        transformMusicState(state: .SUPlayerStatePlaying)
    }
    
    func transformMusicState(state:SUPlayerState) {
        updateLockScreenInfo()
        self.playState = state//改变状态
        if state == .SUPlayerStatePaused {
            self.musicPlayer?.pause()
        }else {
            self.playMusicWithModel(currendModel)
        }
    }
    
    func updateMusicIndex(increment: Bool) {
        guard !dataSource.isEmpty else { return }
        if increment {
            self.currentIndex = self.getNextIndex() //下一首
        }else {
            self.currentIndex = self.getPreviousIndex() //上一首
        }
    }
    
    var currentIndex: Int? {
        get {
            if let musicModelId = self.currendModel?.id {
                return self.dataSource.firstIndex { $0.id == musicModelId }
            }
            return nil
        }
        set {
            if let newIndex = newValue, newIndex >= 0, newIndex < self.dataSource.count {
                self.currendModel = self.dataSource[newIndex]
            } else {
                self.currendModel = nil
            }
        }
    }
    func getNextIndex() -> Int {
        if let currentIndex = self.currentIndex {
            let nextIndex = currentIndex + 1
            if nextIndex < self.dataSource.count {
                return nextIndex
            } else {
                return 0
            }
        } else {
            return 0
        }
    }
    
    func getPreviousIndex() -> Int {
        if let currentIndex = self.currentIndex {
            let previousIndex = currentIndex - 1
            if previousIndex >= 0 {
                return previousIndex
            } else {
                return self.dataSource.count - 1
            }
        } else {
            return self.dataSource.count - 1
        }
    }
    
    func updateLockScreenInfo(){
        // 注册后台播放
        if currendModel == nil {
            return
        }
        var nowPlayingInfo: [String: Any] = [:]
        let albumArt = MPMediaItemArtwork(boundsSize: CGSize(width: 512, height: 512), requestHandler: { (size) -> UIImage in
            return UIImage(named: "icon_music_def")! })
        if let model = self.currendModel {
            nowPlayingInfo = [ MPMediaItemPropertyTitle: model.title ?? "",
                              MPMediaItemPropertyArtist: model.lyric_desc ?? "",
                          MPMediaItemPropertyAlbumTitle: model.title ?? "",
                   MPNowPlayingInfoPropertyPlaybackRate: 1.0,
                             MPMediaItemPropertyArtwork: albumArt,
                    MPMediaItemPropertyPlaybackDuration: CMTimeGetSeconds(musicPlayer?.currentItem?.duration ?? CMTime()), //总时长
            MPNowPlayingInfoPropertyElapsedPlaybackTime: CMTimeGetSeconds(musicPlayer?.currentItem?.currentTime() ?? CMTime())]
            if let thumbnail = model.cover_url, let imageURL = URL(string: thumbnail) {
                SDWebImageManager.shared.loadImage(with: imageURL, options: .continueInBackground, progress: nil) { image, _, _, _, _, _ in
                    let albumArt = MPMediaItemArtwork(boundsSize: CGSize(width: 512, height: 512)) { _ in image ?? UIImage(named: "icon_music_def")! }
                    nowPlayingInfo[MPMediaItemPropertyArtwork] = albumArt
                    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
                }
            }
        }
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status", let playerItem = object as? AVPlayerItem {
            switch playerItem.status {
            case .readyToPlay:
                playState = .SUPlayerStatePlaying
            case .failed:
                playState = .SUPlayerStateError
            case .unknown:
                playState = .SUPlayerStateStopped
            @unknown default:
                break
            }
        } else if keyPath == "rate", let player = object as? AVPlayer {
            let newRate = change?[.newKey] as? Float ?? 0.0
            if newRate == 0.0 {
                playState = .SUPlayerStatePaused
            } else if newRate == 1.0 {
                playState = .SUPlayerStatePlaying
            }
        } else if keyPath == "timeControlStatus", let player = object as? AVPlayer {
            if #available(iOS 10.0, *) {
                switch player.timeControlStatus {
                case .paused:
                    playState = .SUPlayerStatePaused
                case .waitingToPlayAtSpecifiedRate:
                    playState = .SUPlayerStateBuffering
                case .playing:
                    playState = .SUPlayerStatePlaying
                @unknown default:
                    break
                }
            }
        } else if keyPath == "playbackLikelyToKeepUp", let playerItem = object as? AVPlayerItem {
            if playerItem.isPlaybackLikelyToKeepUp {
                if musicPlayer?.rate == 0 {
                    musicPlayer?.play()
                }
            } else {
                playState = .SUPlayerStateBuffering
            }
        } else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
}
